﻿using Agility.Web.Models.DomainModel;
using NUnit.Framework;
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Globalization;
using System.ServiceModel.DomainServices.Server;
using System.Collections.Generic;
using Agility.Web.Resources;

namespace Agility.Testing.Web.Requirements
{
    [TestFixture]
    public class AssessmentTests
    {
        Assessment assessment;
        Assessment.AssessmentMetadata assessmentMetadata;

        [TestFixtureSetUp]
        public void SetupTestFixture()
        {
        }

        [TestFixtureTearDown]
        public void TeardownTestFixture()
        {
        }

        [SetUp]
        public void SetupTest()
        {
            assessment = Assessment.CreateAssessment(Guid.NewGuid(), DateTime.Today);
            assessmentMetadata = new Assessment.AssessmentMetadata();
        }

        [TearDown]
        public void TeardownTest()
        {
            assessmentMetadata = null;
        }

        [Test]
        [Category("UnitTest")]
        public void TestCreationDate()
        {
            DateTime today = DateTime.Today;
            Assert.AreEqual(today, assessment.CreationDate);
        }

        [Test]
        [Category("UnitTest")]
        public void TestEffortSize()
        {
            int expected = 3;
            assessment.EffortSize = expected;
            Assert.AreEqual(expected, assessment.EffortSize);
        }

        [Test]
        [Category("UnitTest")]
        public void TestPotentialBusinessValue()
        {
            int expected = 3;
            assessment.PotentialBusinessValue = 3;
            Assert.AreEqual(expected, assessment.PotentialBusinessValue);
        }

        [Test]
        [Category("UnitTest")]
        public void TestStrategyAlignment()
        {
            decimal expected = 0.5M;
            assessment.StrategyAlignment = expected;
            Assert.AreEqual(expected, assessment.StrategyAlignment);
        }

        [Test]
        [Category("UnitTest")]
        [NUnit.Framework.Ignore("Ignore while Assessments are not used.")]
        public void TestRankingValue()
        {
            decimal expected = 1.5M;
            assessment.EffortSize = 2;
            assessment.PotentialBusinessValue = 6;
            assessment.StrategyAlignment = 0.5M;
            Assert.AreEqual(expected, assessment.RankingValue);
        }

        [Test]
        [Category("UnitTest")]
        public void TestMetadataTypeAttribute()
        {
            // Arrange
            var actual = typeof(Assessment).GetCustomAttributes(typeof(MetadataTypeAttribute), false)
                                        .Cast<MetadataTypeAttribute>()
                                        .FirstOrDefault();
            string missingMessage = "MetaDataAttribute is missing on Assessment";
            string wrongTypeMessage = "MetadataTypeAttribute uses the wrong type on Assessment";

            // Assert
            Assert.NotNull(actual, missingMessage);
            Assert.AreEqual(typeof(Assessment.AssessmentMetadata), actual.MetadataClassType, wrongTypeMessage);
        }

        [Test]
        [Category("UnitTest")]
        public void TestKeyAttribute()
        {
            // Arrange
            var target = typeof(Assessment.AssessmentMetadata).GetProperty("Id");
            var actual = target.GetCustomAttributes(typeof(KeyAttribute), false)
                                        .Cast<KeyAttribute>()
                                        .FirstOrDefault();
            string message = "RequiredAttribute is missing on Assessment.Id";

            // Assert
            Assert.NotNull(actual, message);
        }

        [Test]
        [Category("UnitTest")]
        [TestCase("CreationDate", TestName = "CreationDate")]
        [TestCase("Id", TestName = "Id")]
        [TestCase("IsApproved", TestName = "IsApproved")]
        public void TestEditableAttribute(string propertyName)
        {
            // Arrange
            var target = typeof(Assessment.AssessmentMetadata).GetProperty(propertyName);
            var actual = target.GetCustomAttributes(typeof(EditableAttribute), false)
                                        .Cast<EditableAttribute>()
                                        .FirstOrDefault();
            string missingMessage = string.Format(CultureInfo.InvariantCulture, "EditableAttribute is missing on Assessment.{0}", propertyName);
            string valueMessage = string.Format(CultureInfo.InvariantCulture, "EditableAttribute is set incorrectly on Assessment.{0}", propertyName);

            // Assert
            Assert.NotNull(actual, missingMessage);
            Assert.IsFalse(actual.AllowEdit, valueMessage);
        }

        [Test]
        [Category("UnitTest")]
        [TestCase("StrategyAlignment", 0, 1, TestName = "StrategyAlingment")]
        public void TestRangeAttribute(string propertyName, int minimum, int maximum)
        {
            // Arrange
            var target = typeof(Assessment.AssessmentMetadata).GetProperty(propertyName);
            var actual = target.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.RangeAttribute), false)
                                                    .Cast<System.ComponentModel.DataAnnotations.RangeAttribute>()
                                                    .FirstOrDefault();
            string isMissingMessage = string.Format(CultureInfo.InvariantCulture, "RangeAttribute is missing on Assessment.{0}", propertyName);
            string minimumMessage = string.Format(CultureInfo.InvariantCulture, "Minimum is not set correctly on Assessment.{0}", propertyName);
            string maximumMessage = string.Format(CultureInfo.InvariantCulture, "Maximum is not set correctly on Assessment.{0}", propertyName);

            // Assert
            Assert.NotNull(actual, isMissingMessage);
            Assert.AreEqual(minimum, actual.Minimum, minimumMessage);
            Assert.AreEqual(maximum, actual.Maximum, maximumMessage);
        }

        [Test]
        [Category("UnitTest")]
        [TestCase("CreationDate", true, 5, "AssessmentCreationDate", typeof(AssessmentResources), TestName = "CreationDate")]
        [TestCase("EffortSize", true, 0, "AssessmentEffortSize", typeof(AssessmentResources), TestName = "EffortSize")]
        [TestCase("PotentialBusinessValue", true, 1, "AssessmentPotentialBusinessValue", typeof(AssessmentResources), TestName = "PotentialBusinessValue")]
        [TestCase("StrategyAlignment", true, 2, "AssessmentStrategyAlignment", typeof(AssessmentResources), TestName = "StrategyAlignment")]
        [TestCase("RankingValue", true, 3, "AssessmentRankingValue", typeof(AssessmentResources), TestName = "RankingValue")]
        [TestCase("IsApproved", true, 4, "AssessmentIsApproved", typeof(AssessmentResources), TestName = "IsApproved")]
        [TestCase("Id", false, 0, null, null, TestName = "Id")]
        public void TestDisplayAttribute(string propertyName, bool autoGenerate, int order, string name, Type resourceType)
        {
            // Arrange
            var target = typeof(Assessment.AssessmentMetadata).GetProperty(propertyName);
            var actual = target.GetCustomAttributes(typeof(DisplayAttribute), false)
                                                    .Cast<DisplayAttribute>()
                                                    .FirstOrDefault();

            // Assert
            Assert.NotNull(actual, string.Format(CultureInfo.InvariantCulture, "DisplayAttribute is missing on Assessment.{0}", propertyName));
            Assert.AreEqual(autoGenerate, actual.GetAutoGenerateField().GetValueOrDefault(true), string.Format(CultureInfo.InvariantCulture, "AutoGeneratingField is set incorrectly on Assessment.{0}", propertyName));
            Assert.AreEqual(order, actual.GetOrder().GetValueOrDefault(0), string.Format(CultureInfo.InvariantCulture, "Order is set incorrectly on Assessment.{0}", propertyName));
            Assert.AreEqual(name, actual.Name, string.Format(CultureInfo.InvariantCulture, "The resource name is set incorrectly on Assessment.{0}", propertyName));
            Assert.AreEqual(resourceType, actual.ResourceType, string.Format(CultureInfo.InvariantCulture, "Assessment.{0} is using the wrong resource file", propertyName));
        }

        [Test]
        [Category("UnitTest")]
        [TestCase("Id", TestName = "Id")]
        public void TestDataType(string propertyName)
        {
            var target = typeof(Epic).GetProperty(propertyName);
            var targetMetadata = typeof(Epic.EpicMetadata).GetProperty(propertyName);
            var expected = target.GetType();
            var actual = targetMetadata.GetType();

            // Assert
            Assert.AreEqual(expected, actual, string.Format(CultureInfo.InvariantCulture, "Type of property {0} differs in Assessment ({1}) and AssessmentMetadata ({2})", propertyName, expected.ToString(), actual.ToString()));
        }
    }
}
